﻿using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.EntityFramework.Mappers;
using IdentityServer4.Models;
using K9Cloud.Identity.Authentication.User;
using K9Nano.IdentityServerCore;
using K9Nano.IdentityServerCore.Data;
using K9Nano.MultiTenancy;
using K9Nano.Share;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace K9Cloud.Identity.Data
{
    public class SeedData
    {
        public static IEnumerable<IdentityResource> Ids =>
            new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResources.Phone()
            };

        public static IEnumerable<ApiResource> Apis =>
            new List<ApiResource>
            {
                new ApiResource(K9SharedConstants.IdentityApiName, "认证授权服务")
                {
                    UserClaims =
                    {
                        JwtClaimTypes.Name,
                        JwtClaimTypes.PhoneNumber,
                        JwtClaimTypes.PreferredUserName,
                        K9SharedConstants.TenantIdClaimType
                    },
                }
            };

        public static IEnumerable<Client> Clients =>
            new List<Client>
            {
                // machine to machine client
                new Client
                {
                    ClientId = "client",
                    ClientSecrets = { new Secret("secret".Sha256()) },

                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials ,
                    // scopes that client has access to
                    AllowedScopes = {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        K9SharedConstants.IdentityApiName
                    },
                    Claims =
                    {
                        new Claim(K9SharedConstants.TenantIdClaimType, "1")
                    }
                },
                // interactive ASP.NET Core MVC client
                new Client
                {
                    ClientId = "mvc",
                    ClientSecrets = { new Secret("secret".Sha256()) },

                    AllowedGrantTypes = GrantTypes.Code,
                    RequireConsent = false,
                    RequirePkce = true,
                
                    // where to redirect to after login
                    RedirectUris = { "http://localhost:5002/signin-oidc" },

                    // where to redirect to after logout
                    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        K9SharedConstants.IdentityApiName
                    },

                    AllowOfflineAccess = true,
                    AlwaysSendClientClaims = true,
                    Claims =
                    {
                        new Claim(K9SharedConstants.TenantIdClaimType, "1")
                    }
                }
            };

        public static void InitializeDatabase(IApplicationBuilder app)
        {
            using var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope();
            serviceScope.ServiceProvider.GetRequiredService<K9PersistedGrantDbContext>().Database.Migrate();

            var configurationDbContext = serviceScope.ServiceProvider.GetRequiredService<K9ConfigurationDbContext>();
            configurationDbContext.Database.Migrate();
            if (!configurationDbContext.Clients.Any())
            {
                foreach (var client in Clients)
                {
                    configurationDbContext.Clients.Add(client.ToEntity());
                }
                configurationDbContext.SaveChanges();
            }

            if (!configurationDbContext.IdentityResources.Any())
            {
                foreach (var resource in Ids)
                {
                    configurationDbContext.IdentityResources.Add(resource.ToEntity());
                }
                configurationDbContext.SaveChanges();
            }

            if (!configurationDbContext.ApiResources.Any())
            {
                foreach (var resource in Apis)
                {
                    configurationDbContext.ApiResources.Add(resource.ToEntity());
                }
                configurationDbContext.SaveChanges();
            }

            var oauthDbContext = serviceScope.ServiceProvider.GetRequiredService<K9CloudIdentityDbContext>();
            oauthDbContext.EventsDisabled = true;
            oauthDbContext.FiltersDisabled = true;
            if (!oauthDbContext.Users.IgnoreQueryFilters().Any())
            {
                var userManager = serviceScope.ServiceProvider.GetRequiredService<UserManager<AppUser>>();
                var admin = new AppUser
                {
                    UserName = "admin"
                };
                var result = userManager.CreateAsync(admin, "qwe123")
                       .GetAwaiter()
                       .GetResult();

                result = userManager.AddClaimsAsync(admin, new[]{
                    new Claim(JwtClaimTypes.Name, "Bob Smith"),
                    new Claim(JwtClaimTypes.GivenName, "Bob"),
                    new Claim(JwtClaimTypes.FamilyName, "Smith"),
                    new Claim(JwtClaimTypes.Email, "BobSmith@email.com"),
                    new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                    new Claim(JwtClaimTypes.Profile, "assets/tmp/img/avatar.jpg"),
                    new Claim(JwtClaimTypes.WebSite, "http://bob.com"),
                    new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json),
                    new Claim("location", "somewhere"),
                    new Claim(JwtClaimTypes.Role, "admin,user"),
                    new Claim(K9SharedConstants.TenantIdClaimType, "1")
                }).Result;
            }

            if (!oauthDbContext.Set<Tenant>().Any())
            {
                oauthDbContext.Set<Tenant>()
                    .Add(new Tenant
                    {
                        Name = "yc",
                        DisplayName = "YC"
                    });
                oauthDbContext.SaveChanges();
            }
        }
    }
}